package com.linhngua.code.gwt.spring;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.hibernate.tool.hbm2ddl.Target;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import com.linhngua.code.data.shop.Item;
import com.linhngua.code.hibernate.config.DomainClass;
import com.linhngua.code.hibernate.core.EntityManager;
import com.linhngua.code.hibernate.core.HibernateDataAccess;
import com.linhngua.code.hibernate.core.HibernateOracleDataAccess;

/**
 * 
 * @author tranxl to initialize hibernate
 * 
 */
@Configuration
@Profile({"dev"})
public abstract class HibernateInitSpring {

	@Autowired
	protected DomainClass domainClasses;
	
	



	@Bean
	public LocalSessionFactoryBean sessionFactoryBean() {

		LocalSessionFactoryBean bean = new LocalSessionFactoryBean();
		bean.setDataSource(dataSource());

		bean.setAnnotatedClasses(domainClasses.getDomainClasses());

		Properties hibernateProperties = new Properties();
		hibernateProperties.put("hibernate.dialect", getHibernateDialect());
		// hibernateProperties.put("hibernate.show_sql", true);
		// hibernateProperties.put("hibernate.current_session_context_class",
		// "jta");
		bean.setHibernateProperties(hibernateProperties);

		return bean;
	}

	@Bean
	public SessionFactory sessionFactory() {
		return sessionFactoryBean().getObject();
	}

	abstract DataSource dataSource();

	abstract String getHibernateDialect();

	abstract org.hibernate.cfg.Configuration createConfig();

	final protected void configureDataSource(BasicDataSource dataSource,
			String validationQuery) {

		dataSource.setMaxIdle(10);
		dataSource.setMaxActive(100);
		dataSource.setMaxWait(10000);
		dataSource.setValidationQuery(validationQuery);
		dataSource.setTestOnBorrow(false);
		dataSource.setTestWhileIdle(true);
		dataSource.setTimeBetweenEvictionRunsMillis(120000);
		dataSource.setMinEvictableIdleTimeMillis(1800000);
		dataSource.setNumTestsPerEvictionRun(5);
		dataSource.setDefaultAutoCommit(false);
	}

	final void upgradeSchema(DataSource dataSource) {

		org.hibernate.cfg.Configuration config = createConfig();

		for (Class<?> domainClass : domainClasses.getDomainClasses()) {
			config.addAnnotatedClass(domainClass);
		}

		SchemaUpdate schemaUpdate = new SchemaUpdate(config);
		schemaUpdate.execute(true, true);
	}

	final void applySchema(DataSource dataSource) {

		org.hibernate.cfg.Configuration config = createConfig();

		for (Class<?> domainClass : domainClasses.getDomainClasses()) {
			config.addAnnotatedClass(domainClass);
		}

		SchemaExport schemaExport = new SchemaExport(config);
		schemaExport.execute(Target.BOTH, SchemaExport.Type.BOTH);
	}
	
	//dao
	@Bean
	@Qualifier("ItemDataAccess")
	public HibernateDataAccess<Integer, Item> itemDataAccess() {

		return new HibernateOracleDataAccess<Integer, Item>(sessionFactory());
	}
	
	@Bean
	@Qualifier("itemManager")
	public EntityManager<Integer, Item> itemManager(){
		return new EntityManager<Integer, Item>(itemDataAccess());
	}
}
